#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include "debug.h"
#include "os_api.h"
#include "dev_api.h"
#include "ps_api.h"
#include "file_api.h"
#include "dtu_mqtt.h"

#include "core_mqtt.h"

#define mqtt_printf(fmt, ...) LOG_PRINTF(fmt, ##__VA_ARGS__)

#define MQTTCFG_NVM_FILE	"mqttcfg_nvm.info"

static mqtt_info_t local_mqtt_info = {0};

typedef struct
{
    int len; 	
    void *data; 
}mqtt_pub_msg_t;

static OSMsgQRef mqtt_pub_msgq = NULL;


static OSMutexRef mqttcfgMuteRef = NULL;

void mqttcfgMutexInit(void)
{
	OSA_STATUS status;
	status = OSAMutexCreate(&mqttcfgMuteRef, OS_PRIORITY);
	ASSERT(status == OS_SUCCESS);
}

void mqttcfgMutexLock(void)
{
	OSA_STATUS status;
	status = OSAMutexLock(mqttcfgMuteRef, OSA_SUSPEND);
	ASSERT(status == OS_SUCCESS);
}

void mqttcfgMutexUnlock(void)
{
	OSA_STATUS status;
	status = OSAMutexUnlock(mqttcfgMuteRef);
	ASSERT(status == OS_SUCCESS);
}

void mqttcfg_init(void)
{
#if 0
	FILE_ID fd;	
	mqtt_info_t temp_mqtt_info = {0};

	mqttcfgMutexInit();	

	fd = FDI_fopen(MQTTCFG_NVM_FILE, "rb");
	if (fd != 0) 
	{
		mqtt_printf("read %s!\n", MQTTCFG_NVM_FILE);	
		FDI_fseek(fd, 0, SEEK_SET);
		FDI_fread(&temp_mqtt_info, sizeof(mqtt_info_t), 1, fd);
		FDI_fclose(fd);	
	}

	mqttcfgMutexLock();
	memset(&local_mqtt_info, 0x00, sizeof(mqtt_info_t));
	memcpy(&local_mqtt_info, &temp_mqtt_info, sizeof(mqtt_info_t));	
	mqttcfgMutexUnlock();
#else
	FILE_ID fd;	

	mqttcfgMutexInit();	

	mqttcfgMutexLock();
	memset(&local_mqtt_info, 0x00, sizeof(mqtt_info_t));

	fd = FDI_fopen(MQTTCFG_NVM_FILE, "rb");
	if (fd != 0) 
	{
		mqtt_printf("read %s!\n", MQTTCFG_NVM_FILE);	
		FDI_fseek(fd, 0, SEEK_SET);
		FDI_fread(&local_mqtt_info, sizeof(mqtt_info_t), 1, fd);
		FDI_fclose(fd);	
	} else {
		local_mqtt_info.tls = 1;
		local_mqtt_info.clean = CORE_MQTT_DEFAULT_CLEAN_SESSION;
		local_mqtt_info.heartbeat = CORE_MQTT_DEFAULT_HEARTBEAT_INTERVAL_MS;
	}
	mqttcfgMutexUnlock();
#endif
}

mqtt_info_t * mqttcfg_get(void)
{
	return &local_mqtt_info;
}

void mqttcfg_update_nvm(void)
{
	FILE_ID fd;

	mqtt_info_t temp_mqtt_info = {0};
#if 0
	mqttcfgMutexLock();
	memset(&temp_mqtt_info, 0x00, sizeof(mqtt_info_t));
	memcpy(&temp_mqtt_info, &local_mqtt_info, sizeof(mqtt_info_t));	
	mqttcfgMutexUnlock();

	fd = FDI_fopen(MQTTCFG_NVM_FILE, "wb");
	if (fd != 0)
	{
		mqtt_printf("write %s!\n", MQTTCFG_NVM_FILE);
		FDI_fwrite(&temp_mqtt_info, sizeof(mqtt_info_t), 1, fd);
		FDI_fclose(fd);
	}	
#else
	mqttcfgMutexLock();
	fd = FDI_fopen(MQTTCFG_NVM_FILE, "wb");
	if (fd != 0)
	{
		mqtt_printf("write %s!\n", MQTTCFG_NVM_FILE);
		FDI_fwrite(&local_mqtt_info, sizeof(mqtt_info_t), 1, fd);
		FDI_fclose(fd);
	}	
	mqttcfgMutexUnlock();
#endif
}

void mqttcfg_remove(void)
{
    FDI_remove(MQTTCFG_NVM_FILE);
}

extern void dtu_uart_log(char *log);
extern void send_to_uart(char *buffer, int length);
extern int mqtt_basic_demo(mqtt_info_t *mqtt_ptr,  int register_mdoe);
extern int mqtt_basic_demo_with_client(mqtt_info_t *mqtt_ptr);
extern int dynreg_basic_demo(mqtt_info_t *mqtt_ptr);
extern int dynregmq_basic_demo(mqtt_info_t *mqtt_ptr, int skip_pre_regist_flag);
extern int demo_mqtt_publish(char *data, int len);

extern int demo_mqtt_is_connected(void);

void send_uart_data_to_mqtt(char *data, int len)
{
	char *tempbuf = NULL;
	OSA_STATUS osa_status;
	mqtt_pub_msg_t pubmsg;

	if (mqtt_pub_msgq == NULL || data == NULL || len <= 0 || !demo_mqtt_is_connected()){
		mqtt_printf("mqtt not ready!\n");
		return;
	}

	mqtt_printf("send_uart_data_to_mqtt , len: %d, data %s\n", len, data);

	tempbuf  = (char *)malloc(len+1);
	memset(tempbuf, 0x00, len+1);
	memcpy(tempbuf, (char *)data, len);

	memset(&pubmsg, 0x00, sizeof(mqtt_pub_msg_t));	
	pubmsg.len= len;
	pubmsg.data = tempbuf;

	osa_status = OSAMsgQSend(mqtt_pub_msgq, sizeof(mqtt_pub_msg_t), (UINT8*)&pubmsg, OSA_NO_SUSPEND);
	mqtt_printf("send_uart_data_to_mqtt, osa_status: %d\n", osa_status);

	if (osa_status != OS_SUCCESS && tempbuf){
		free(tempbuf);
	}
}

void send_mqtt_data_to_uart(char *data, int len)
{
	mqtt_printf("send_mqtt_data_to_uart , len: %d, data %s\n", len, data);
	
	send_to_uart(data, len);
}

void dtu_mqtt_app_start(void)
{	
	int res;
	OS_STATUS status;

	int max_try = 20;

	int pub_failed_count = 0;	
	int network_lost_count = 0;
	
	mqtt_pub_msg_t pub_msg = {0};

	mqtt_info_t *mqtt_ptr = mqttcfg_get();

	/*creat msgq*/
	status = OSAMsgQCreate(&mqtt_pub_msgq, "mqtt_pub_msgq", sizeof(mqtt_pub_msg_t), 128, OS_FIFO);
	ASSERT(status == OS_SUCCESS);
	
	mqtt_printf("%s: starting...\n", __FUNCTION__);

	mqttcfg_init();
			
	if  ((mqtt_ptr->mode == 0 && strlen(mqtt_ptr->host) && strlen(mqtt_ptr->clientid))
		||(mqtt_ptr->mode == 1 && strlen(mqtt_ptr->host) && strlen(mqtt_ptr->productkey) && strlen(mqtt_ptr->devicename) && (strlen(mqtt_ptr->devicesecret) || strlen(mqtt_ptr->productsecret)))) {
		// config ok
	} else {
		dtu_uart_log("read mqttcfg failed, goto exit");
		goto exit;
	}

	while(max_try--){
		
		int retvalue; 
		char new_device_secret[MQTT_CFG_MAX_LEN] = {0};

		if (mqtt_ptr->mode == 0 ){
			
			mqtt_printf("clientid: %s\n", mqtt_ptr->clientid);
			mqtt_printf("username: %s\n", mqtt_ptr->username);
			mqtt_printf("password: %s\n", mqtt_ptr->password);
			
			if ( strlen(mqtt_ptr->clientid)  > 0){

				dtu_uart_log("will connect mqtt server");

				retvalue = mqtt_basic_demo(mqtt_ptr, 0x7f);
				if (retvalue == 0) {
					dtu_uart_log("connect mqtt server succeed");

					max_try = 20;
					break;
				}else{
					dtu_uart_log("connect mqtt server failed");
				
					OSATaskSleep(2*200);
					continue;
				}
			} else {
				dtu_uart_log("clientid, username or password is error, goto exit");

				goto exit;
			}				
		}

		if (mqtt_ptr->mode == 1 &&  mqtt_ptr->register_mode == 0 ){

			mqtt_printf("productkey: %s\n", mqtt_ptr->productkey);
			mqtt_printf("devicename: %s\n", mqtt_ptr->devicename);
			mqtt_printf("devicesecret: %s\n", mqtt_ptr->devicesecret);
			
			if ( strlen(mqtt_ptr->productkey)  > 0
				&& strlen(mqtt_ptr->devicename)  > 0
				&& strlen(mqtt_ptr->devicesecret)  > 0){

				dtu_uart_log("will connect aliyun mqtt server, register_mode is 0");
				
				retvalue = mqtt_basic_demo(mqtt_ptr, 0);
				if (retvalue == 0) {
					dtu_uart_log("sucess connect aliyun mqtt server, register_mode is 0");			
					max_try = 20;
					break;
				}else{
					dtu_uart_log("fail connect aliyun mqtt server, register_mode is 0, retry");
					OSATaskSleep(2*200);
					continue;
				}
			} else {
				dtu_uart_log("productkey, devicename or devicesecret is error, goto exit");
			
				goto exit;
			}
		}

		if (mqtt_ptr->mode == 1 &&  mqtt_ptr->register_mode == 1){
			
			if ( strlen(mqtt_ptr->dynregmq_devicesecret) == 0){
				if ( strlen(mqtt_ptr->productkey) > 0 
					&& strlen(mqtt_ptr->devicename) > 0 
					&& strlen(mqtt_ptr->productsecret) > 0){

					dtu_uart_log("dynregmq_basic_demo req dynregmq_devicesecret");			
					//retvalue = dynreg_basic_demo(mqtt_ptr);
					retvalue = dynregmq_basic_demo(mqtt_ptr, 0);
					if (retvalue == 0 && strlen(mqtt_ptr->dynregmq_devicesecret) ){
						mqttcfg_update_nvm();
						max_try = 20;
					}else{
						dtu_uart_log("dynregmq_basic_demo req dynregmq_devicesecret failed, retry");
						OSATaskSleep(2*200);
						continue;
					}
				} else {
					dtu_uart_log("productkey, devicename or productsecret is error, goto exit");
				
					goto exit;
				}
			} 

			mqtt_printf("productkey: %s\n", mqtt_ptr->productkey);
			mqtt_printf("devicename: %s\n", mqtt_ptr->devicename);
			mqtt_printf("dynregmq_devicesecret: %s\n", mqtt_ptr->dynregmq_devicesecret);
			
			if ( strlen(mqtt_ptr->productkey)  > 0
				&& strlen(mqtt_ptr->devicename)  > 0
				&& strlen(mqtt_ptr->dynregmq_devicesecret)  > 0){

				dtu_uart_log("will connect aliyun mqtt server, register_mode is 1");			
				retvalue = mqtt_basic_demo(mqtt_ptr, 1);
				if (retvalue == 0) {
					dtu_uart_log("sucess connect aliyun mqtt server, register_mode is 1");								
					max_try = 20;
					break;
				}else{
					dtu_uart_log("fail connect aliyun mqtt server, register_mode is 1, retry");
					OSATaskSleep(2*200);
					continue;
				}
			} else {
				dtu_uart_log("productkey, devicename or dynregmq_devicesecret is error, goto exit");
			
				goto exit;
			}
			
		} 			

		if (mqtt_ptr->mode == 1 &&  mqtt_ptr->register_mode == 2){
			
			if ( strlen(mqtt_ptr->dynregmq_clientid) == 0){
				if ( strlen(mqtt_ptr->productkey) > 0 
					&& strlen(mqtt_ptr->devicename) > 0 
					&& strlen(mqtt_ptr->productsecret) > 0){
					
					dtu_uart_log("will call dynregmq_basic_demo req dynregmq_clientid, dynregmq_username, dynregmq_password");								
					retvalue = dynregmq_basic_demo(mqtt_ptr, 1);
					if (retvalue == 0 
						&& strlen(mqtt_ptr->dynregmq_clientid)
						&& strlen(mqtt_ptr->dynregmq_username)
						&& strlen(mqtt_ptr->dynregmq_password)){
						mqttcfg_update_nvm();

						dtu_uart_log("dynregmq_basic_demo req dynregmq_clientid, dynregmq_username, dynregmq_password succeed");						
						
						max_try = 20;
					}else{
						dtu_uart_log("dynregmq_basic_demo req dynregmq_clientid, dynregmq_username, dynregmq_password failed");						
					
						OSATaskSleep(2*200);
						continue;
					}
				} else {
					dtu_uart_log("productkey, devicename or productsecret is error, goto exit");
					goto exit;
				}
			} 

			mqtt_printf("dynregmq_clientid: %s\n", mqtt_ptr->dynregmq_clientid);
			mqtt_printf("dynregmq_username: %s\n", mqtt_ptr->dynregmq_username);
			mqtt_printf("dynregmq_password: %s\n", mqtt_ptr->dynregmq_password);
			
			if ( strlen(mqtt_ptr->dynregmq_clientid)  > 0
				&& strlen(mqtt_ptr->dynregmq_username)  > 0
				&& strlen(mqtt_ptr->dynregmq_password)  > 0){

				dtu_uart_log("will connect aliyun mqtt server, register_mode is 2");				
				retvalue = mqtt_basic_demo(mqtt_ptr, 2);
				if (retvalue == 0) {
					dtu_uart_log("sucess connect aliyun mqtt server, register_mode is 2");						
					max_try = 20;
					break;
				}else{
					dtu_uart_log("fail connect aliyun mqtt server, register_mode is 2, retry");				
					OSATaskSleep(2*200);
					continue;
				}
			} else {
				dtu_uart_log("dynregmq_clientid, dynregmq_username or dynregmq_password is error, goto exit");
			
				goto exit;
			}
			
		}

		OSATaskSleep(10);
	}

	if (max_try <= 0){
		dev_CtrlReset(0);
	}
	
	while (1) {
		status = OSAMsgQRecv(mqtt_pub_msgq, (void *)&pub_msg, sizeof(mqtt_pub_msg_t), 3*200/*OSA_SUSPEND*/);

		if (status == OS_SUCCESS && pub_msg.data && pub_msg.len) {

			mqtt_printf("OSAMsgQRecv mqtt_pub_msgq status: %d\n", status);
			
			res = demo_mqtt_publish((char *)pub_msg.data, pub_msg.len);
			mqtt_printf("demo_mqtt_publish res: %d, len: %d, data: %s\n",  res, pub_msg.len, (char *)pub_msg.data);
			if (res < 0){
				pub_failed_count++;
			}else {
				pub_failed_count = 0;
			}
			
			if (pub_failed_count >= 5){
				dev_CtrlReset(1);
			}					
			
			free(pub_msg.data);
			
			pub_msg.data = NULL;
		} 
		
		if (status == OS_TIMEOUT) 	// 3 Ãë³¬Ê±
		{
			// check mqtt pub res and network
			if (ps_GetNetworkReady()){
				network_lost_count = 0;
			} else {
				network_lost_count ++;		
				mqtt_printf("network_lost_count: %d", network_lost_count);						
			}

			if (network_lost_count >= 20){
				dev_CtrlReset(0);
			}			
		}
	}

exit:
	mqtt_printf("%s: exiting...\n", __FUNCTION__);
}


